import unittest

from zope.interface import Interface, implements

from meercat.interfaces import IOrderedRegistry
from meercat.base.registry import OrderedRegistry


class BaseRegistryTests(unittest.TestCase):
    def setUp(self):
        self.registry = OrderedRegistry()
        self.registry.register('first','1')
        self.registry.register('second','2')
        self.registry.register('third','3')


class RegistrationTests(BaseRegistryTests):
    def test_registered(self):
        """ Registering components with no position specified """
        self.assertEqual(list(self.registry), ['1','2','3'])
    
    def test_insert_first(self):
        """ Registering a component first """
        self.registry.register('secondish', '1.9', first=True)
        
        self.assertEqual(list(self.registry),['1.9','1','2','3'])
        self.assert_('secondish' in self.registry.mapping)
    
    def test_insert_last(self):
        """ Registering a component last """
        self.registry.register('secondish', '1.9', last=True)
        
        self.assertEqual(list(self.registry),['1','2','3','1.9'])
        self.assert_('secondish' in self.registry.mapping)
    
    def test_valid_insert_before(self):
        """ Registering a component with a valid before position specified """
        self.registry.register('secondish', '1.9', before='second')
        
        self.assertEqual(list(self.registry),['1','1.9','2','3'])
        self.assert_('secondish' in self.registry.mapping)
        
        self.registry.register('firstish', '0.9', before='first')
        self.assertEqual(list(self.registry),['0.9','1','1.9','2','3'])
        self.assert_('firstish' in self.registry.mapping)
    
    def test_invalid_insert_before(self):
        """ Registering a component with an invalid before position specified """
        self.assertRaises(ValueError, self.registry.register, 'invalid',
                          'value', before='who')
    
    def test_valid_insert_after(self):
        """ Registering a component with a valid after position specified """
        self.registry.register('secondish', '2.9', after='second')
        
        self.assertEqual(list(self.registry),['1','2','2.9','3'])
        self.assert_('secondish' in self.registry.mapping)
        
        self.registry.register('lastish', '3.9', after='third')
        
        self.assertEqual(list(self.registry),['1','2','2.9','3','3.9'])
        self.assert_('lastish' in self.registry.mapping)
    
    def test_invalid_insert_after(self):
        """ Registering a component with an invalid after position specified """
        self.assertRaises(ValueError, self.registry.register, 'invalid',
                          'value', after='who')
    
    def test_replacement(self):
        """ Replace a registered component with a new one, in place """
        self.registry.register('second', 'two')
        
        self.assertEqual(list(self.registry),['1','two','3'])
    
    def test_duplicate(self):
        """ Register a component twice (raises ValueError) """
        self.assertRaises(ValueError, self.registry.register, 'blah','2')

class InterfaceTests(BaseRegistryTests):
    def test_length(self):
        """ Length function on a registry """
        self.assertEqual(len(self.registry), 3)
    
    def test_containment(self):
        """ Containment in a registry """
        self.assert_('first' in self.registry)
        self.assertFalse('fourth' in self.registry)
        self.assert_('fourth' not in self.registry)
    
    def test_getting(self):
        """ Mapping accessor """
        self.assertEqual(self.registry['first'],'1')
        self.assertRaises(KeyError, self.registry.__getitem__,'other')
    
    def test_setting(self):
        """ Mapping mutator """
        self.registry['second'] = '2.1'
        self.assertEqual(list(self.registry),['1','2.1','3'])
        self.registry['fourth'] = '4'
        self.assertEqual(list(self.registry),['1','2.1','3','4'])
    
    def test_deleting(self):
        """ Mapping removal """
        del self.registry['second']
        self.assertEqual(list(self.registry),['1','3'])
        self.assertFalse('second' in self.registry)
        self.assertRaises(KeyError, self.registry.__delitem__,'other')
    
    def test_iterator(self):
        """ Iteration """
        self.assertEqual(list(self.registry),['1','2','3'])


class IDummyInterface(Interface):
    pass

class DummyClass(object):
    implements(IDummyInterface)

class ProvidedTests(unittest.TestCase):
    def setUp(self):
        self.registry = OrderedRegistry(IDummyInterface)
    
    def test_register_valid(self):
        """ Registering a valid object """
        value = DummyClass()
        self.registry.register('name',value)
        self.assertEqual(list(self.registry), [value])
        self.assert_('name' in self.registry)
    
    def test_set_valid(self):
        """ Set a valid object """
        value = DummyClass()
        self.registry['name'] = value
        value2 = DummyClass()
        value2.test = 'blah'
        self.registry['name'] = value2
        self.assertEqual(list(self.registry), [value2])
        self.assert_('name' in self.registry)
    
    def test_register_invalid(self):
        """ Register an invalid object """
        self.assertRaises(TypeError, self.registry.register, 'name', 'value')
    
    def test_set_invalid(self):
        """ Set an invalid object """
        value = DummyClass()
        self.registry['name'] = value
        self.assertRaises(TypeError, self.registry.__setitem__,'name','value')
        

def test_suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(RegistrationTests))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(InterfaceTests))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ProvidedTests))
    return suite

if __name__ == '__main__':
    unittest.TextTestRunner(verbosity=2).run(test_suite())